home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 June: Reference Library / Dev.CD Jun 94.toast / Periodicals / develop / develop Issue 15 / develop 15 code / QD GX Shell / QuickDraw GX Shell (main).c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-03  |  49.9 KB  |  1,628 lines  |  [TEXT/KAHL]

  1. /**
  2.  --
  3.  --        App:        QuickDraw GX Shell
  4.  --
  5.  -- 
  6.  --        Version:    1.0     1/93:    added general QuickDraw GX support & scrolling     
  7.  --                    1.1        4/93:    added support for QuickDraw GX printing and testing to
  8.  --                                    see is QuickDraw GX is installed.
  9.  --
  10.  --
  11.  --        File:        QuickDraw GX Shell (main).c
  12.  --
  13.  --        Comments:    This code demonstrates scrolling of a window containing QuickDraw GX shapes.
  14.  --                    I create a window in the CreateDocumentWindow function. At this point, I attach a 
  15.  --                    parent viewPort to the window, and a child viewPort to the parent. This 
  16.  --                    approach enables our application to accommodiate scroll bars and adjust
  17.  --                    the child viewPort's mapping to reflect scrolling of the window's contents.
  18.  --
  19.  --                    You might be wondering, why not just perform the same actions on the parent
  20.  --                    viewPort attached to the window? You cannot manipulate the viewPort attached
  21.  --                    to the window. All of it's attributes are maintained by the QuickDraw GX system. 
  22.  --                    This leads to a clipping problems because scroll bars are not really part of the
  23.  --                    window's definition.
  24.  --
  25.  --                    Therefore, we attach the child viewPort to set it's clip shape within the
  26.  --                    scroll bars. Also, we update the mapping of this viewPort when the user scrolls,
  27.  --                    thereby guaranteeing that all of the shapes are re-drawn in their correct location.
  28.  --                    Another approach, would be to update the location of each shape contained in the 
  29.  --                    window after scrolling. This would require a lot of work on the application's part. 
  30.  --                    You would also need to undo this operation at print time because your shapes 
  31.  --                    would not reside in their correct location relative to a page.
  32.  --
  33.  --                    If you are interested in finding the QuickDraw GX additions required to run on a
  34.  --                    QuickDraw GX system, search for "QuickDraw GX Additions". If you are only 
  35.  --                    interested in the additions required to support scrolling in a GX world,
  36.  --                    search on "QuickDraw GX Scrolling". 
  37.  --
  38.  --
  39.  --        Components:    QuickDraw GX Shell (main).c
  40.  --                    QuickDraw GX Shell (main).h
  41.  --                    QuickDraw GX Shell - print.c
  42.  --                    QuickDraw GX Shell - print.h
  43.  --                    QuickDraw GX Shell - scroll.c
  44.  --                    QuickDraw GX Shell - scroll.h
  45.  --                    QuickDraw GX Shell (main).π.rsrc
  46.  --
  47.  --                    The file titled: "QuickDraw GX - print.c" contains of the code required to 
  48.  --                    print the contents of the window.
  49.  --
  50.  --                    The file titled: "QuickDraw GX Shell - scroll.c" contains of the code required to 
  51.  --                    maintain, draw, update the scroll bars, and scroll the contents of the window.
  52.  --        
  53.  --        
  54.  --        QuickDraw GX
  55.  --        Libraries
  56.  --        Used:        This application uses the following QuickDraw GX library code files:
  57.  --                    "color library.c", "font library.c", "graphics debug library.c",
  58.  --                    "layout library.c", "shape library.c", and "transform library.c",  
  59.  --        
  60.  --        
  61.  --        Bugs:        If you zoom the window onto a montior which is bigger than the default, you
  62.  --                    will receive a GRAPHICS WARNING about how the point does not intersect the 
  63.  --                    current viewPort. From that point on, until you resize the window to a smaller
  64.  --                    size scrolling will not work correctly. You can create this problem by zooming
  65.  --                    from an Apple 16" monitor to a portrait monitor. We are currently working on 
  66.  --                    resolving this problem.
  67.  --
  68.  --
  69.  --        Notes:        1) Print this file in landscape for the best results
  70.  --                    2) If you are using THINK C v5.x, I have added THINK markers to navigate the code.
  71.  --                    3) This code was adapted and simplyified from the "DTS AE Skeleton" sample.
  72.  --
  73.  --
  74.  --        Author:        Pete "Luke" Alexander
  75.  --                    Developer Technical Support
  76.  --                    AppleLink: DEVSUPPORT
  77.  --
  78.  --        
  79.  --        ©1992 - 1993  Apple Computer, Inc. 
  80.  --
  81.  **/
  82.  
  83. #include <AppleEvents.h>
  84. #include <Desk.h>
  85. #include <Dialogs.h>
  86. #include <DiskInit.h>
  87. #include <Errors.h>
  88. #include <Fonts.h>
  89. #include <GestaltEqu.h>
  90. #include <Menus.h>
  91. #include <Memory.h>
  92. #include <OSEvents.h>
  93. #include <OSUtils.h>
  94. #include <Quickdraw.h>
  95. #include <Resources.h>
  96. #include <Script.h>
  97. #include <StandardFile.h>
  98. #include <ToolUtils.h>
  99. #include <Windows.h>
  100.  
  101. #include "QuickDraw GX Shell (main).h"
  102. #include "QuickDraw GX Shell - scroll.h"
  103.  
  104. //
  105. //    The following interface files are for QuickDraw GX.
  106. //
  107. #include "font library.h"
  108. #include "graphics toolbox.h"
  109. #include "graphics routines.h"
  110. #include "graphics libraries.h"
  111. #include "graphics debugging.h"
  112.  
  113. #include "layout library.h"
  114. #include "layout routines.h"
  115. #include "layout feature constants.h"
  116.  
  117. #include "PrintingManager.h"
  118.  
  119.  
  120. /* This routine is part of the MPW runtime library. This external
  121.    reference to it is done so that we can unload its segment, %A5Init. */
  122. #ifndef THINK_C
  123.   extern void _DataInit();
  124. #endif
  125.  
  126.  
  127. //
  128. // Global Variables
  129. //
  130. Boolean                gDone;            /* Has the user selected quit? */
  131.  
  132.  
  133. //
  134. //    The variables from this point on, were added to support QuickDraw™ GX.
  135. //
  136.  
  137. //
  138. //    gGraphicsClient contains the clien we create within the QuickDrawGXInit function.
  139. //
  140. gxGraphicsClient     gGraphicsClient;
  141.  
  142. //
  143. //    gthePage contain all of the GX shapes which are displayed in the window. gthePage is defined
  144. //    as a pictureType in the function CreateShapes. CreateShapes creates all of the shapes
  145. //    contained in gthePage.
  146. // 
  147. gxShape                gthePage;
  148.  
  149. //
  150. //    This viewPort is the child attached to the window's parent viewPort. Since it is a child viewPort,
  151. //    we (the application) need to maintain the clip shape. We also have the ability to manipulate this
  152. //    viewPort as we see fit, therefore we adjust the mapping, to reflect scrolling changes by the user.
  153. //
  154. gxViewPort            gcontentViewPort;
  155.  
  156. //
  157. //    gDocumentJob contains the gxJob whihc is used a print time. The boolean gQDGXPrintingInstalled 
  158. //    is used to detemrine,if the user has installed printing, if not, we will still run without
  159. //    any printing functionality.
  160. //
  161. gxJob                gDocumentJob;
  162. Boolean             gQDGXPrintingInstalled = false;
  163.  
  164. // 
  165. //    If gDebugging = TRUE, graphics library errors and notices will be posted.  This functionality  will only work with 
  166. //    the "debugging" version of the Secret Graphics init. If this version of the init is not installed, nothing bad will happen, 
  167. //    but these  functions will not work. The "debugging" version of the Secret Graphics init is approximately 700K.
  168. //
  169. Boolean                gDebugging = true;
  170.  
  171. //
  172. //  Set gGiveMeValidation = TRUE, if you will receive run-time validation. 
  173. //
  174. Boolean                gGiveMeValidation = true;
  175.  
  176.  
  177. //     
  178. //    gGraphicsHeapSize sets the size of the QuickDraw heap created by calling the NewGraphicsClient 
  179. //    routine in our QuickDrawGXInit function. You can determine the amount of graphics heap required
  180. //  by using GraphicsBug. In general, you would like to have a few blocks left over. With the 
  181. //    QuickDraw GX v1.0b1 build, this app need the gGraphicsHeapSize set to 115k, to receive reliable
  182. //    printing results to the LaserWriter IISC.
  183. //
  184. long                gGraphicsHeapSize = 115;
  185.  
  186.  
  187.  
  188. /**----- main --------------------------------------------------------------------------------
  189.  --
  190.  --     Main initializes the application memory, toolbox, menubar, the GX world, and global 
  191.  --        variables. We also create a document & window containing our GX picture, which contains
  192.  --        all of our rectangles.
  193.  --
  194.  **/
  195. main()
  196. {
  197.     CursHandle        theCurs; 
  198.  
  199. #ifndef THINK_C
  200.     UnloadSeg((Ptr) _DataInit);        /* note that _DataInit must not be in Main! */
  201. #endif
  202.  
  203.     ToolBoxInit();
  204.     MenuBarInit();
  205.     
  206.     theCurs = GetCursor(watchCursor);
  207.     SetCursor(*theCurs);
  208.  
  209.     //
  210.     //    If QuickDraw GX has not been installed, alert the use aand quit.
  211.     //
  212.     if (!QuickDrawGXInstalled())
  213.       ErrorAlert(kNoQDGXErr, true);
  214.     
  215.     QuickDrawGXInit();        //    This function initializes the GX system
  216.  
  217.     gDone = false;            
  218.  
  219.     CreateDocumentWindow(nil, "\p Cool QuickDraw GX Shapes? ");
  220.  
  221.     SetCursor(&qd.arrow);  
  222.  
  223.     while (!gDone)
  224.         HandleEvent();
  225.     
  226.     ExitToShell();    
  227. }
  228.  
  229.  
  230. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  231. //
  232. //    The following two functions: QuickDrawGXInstalled and QuickDrawGXInit
  233. //
  234. //    Are used to: determine if QuickDraw GX was installed, and intializing the entire GX world.
  235. //    
  236. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  237.  
  238. /**----- QuickDrawGXInstalled ----------------------------------------------------------------
  239.  --
  240.  --        This function determines, if QuickDraw GX has been installed. If it has everything is
  241.  --        great! Otherwise we will return false to the caller.
  242.  --                                                                       (QuickDraw GX Addition)
  243.  **/
  244. Boolean QuickDrawGXInstalled ()
  245. {
  246.     long    theFeatureInQuestion;
  247.     
  248.     //
  249.     //    The QuickDraw GX system requires System 7.1 or newer
  250.     //
  251.     if (Gestalt('grfx', &theFeatureInQuestion) == noErr)
  252.     {
  253.         if (Gestalt('pmgr', &theFeatureInQuestion) == noErr)
  254.             gQDGXPrintingInstalled = true;
  255.         return(true);
  256.     }
  257.     return(false);
  258. }
  259.  
  260.  
  261.  
  262. /**----- QuickDrawGXInit ---------------------------------------------------------------------
  263.  --
  264.  --        This function makes all of the calls required to initialize the GX system.
  265.  --        For complete details regarding each call, please see the comment blocks.
  266.  --                                                                       (QuickDraw GX Addition)
  267.  --                                                 
  268.  **/
  269. void QuickDrawGXInit(void)
  270. {
  271.     //     
  272.     //    The NewGraphicsClient routine defines the QuickDraw GX heap size. If you do not make 
  273.     //    this call, the GX system will create this heap automatically. How? It will create a 
  274.     //    QuickDraw GX heap of 600k. This call allows you to explicity define the amount of 
  275.     //    memory used by the QuickDraw GX system to store it's graphics objects heap.
  276.     //
  277.     //    If you do not pass a value for gGraphicsHeapSize, you will receive the default graphics heap.
  278.     //    The GX system will automatically page objects to disk when memory is low.
  279.     //
  280.     gGraphicsClient = GXNewGraphicsClient(nil, gGraphicsHeapSize * 1024, 0L);
  281.  
  282.  
  283.     // 
  284.     //    If gDebugging = TRUE, you will receive graphics library errors, warnings & notices will
  285.     //    be posted.  This functionality will only work with the "debugging" version of the 
  286.     //    Secret Graphics init.  If this init is not installed, these functions will not work, nor
  287.     //    willl anything bad happen. The "debugging" version of the Secret Graphics init is 
  288.     //    approximately 810K.
  289.     //
  290.     if (gDebugging) {
  291.         SetGraphicsLibraryErrors ();
  292.         SetGraphicsLibraryNotices();    
  293.     }
  294.  
  295.     // 
  296.     //    Set  "gGiveMeValidation" to TRUE, if you want run-time validation. As you increase the amount
  297.     //    of validation, The drawing speed will SLOW down due to all of the internal checking. 
  298.     //    
  299.     //    gxPublicValidation will check parameters to public routines. For additional details regarding 
  300.     //    the various levels of validation, please see the documentation.
  301.     //
  302.     if (gGiveMeValidation) GXSetValidation(gxPublicValidation); 
  303.  
  304.  
  305.     //
  306.     //  Create the default data structures.
  307.     //
  308.     GXEnterGraphics();
  309.  
  310.     //
  311.     //     Initailize the GX printing system, if the user has installed it. If the user has not 
  312.     //    installed the printing system, alert the user to this fact and tell him that drawing
  313.     //    into the window will still work, without any printing capabilities.
  314.     //
  315.     if (gQDGXPrintingInstalled)
  316.       gDocumentJob = PrintInit ();
  317.     else ErrorAlert(kNoQDGXPrintingErr, false);
  318.     
  319.     
  320.     //
  321.     //    Initialize the common colors library defined in "color library.c" and "graphics library.h".
  322.     //    This library is a simple method available for you to color an object quickly by calling the
  323.     //    the SetShapeCommonColor(...) function.
  324.     //
  325.      InitCommonColors();
  326. }
  327.  
  328.  
  329. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  330. //
  331. //    The following four functions: CreateDocumentWindow, CreateThePageOfGXShapes, 
  332. //                                  CreateTextShape, and CreateLayoutShape.
  333. //
  334. //    Are used to: create a window and attach 2 view ports to the window, create a QuickDraw
  335. //    GX pictures, which contains our text and layout shapes.
  336. //    
  337. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  338.  
  339.  
  340.  
  341. /**----- CreateDocumentWindow ----------------------------------------------------------------
  342.  --
  343.  --        This function creates a new document window.  We attached a parent viewPort to the 
  344.  --        window and a child viewPort to it. Having the application maintain the child viewPort's
  345.  --        clip shape and mapping will allow use to draw within the scroll bars & update it's
  346.  --        mapping to reflect scrolling of the shapes.
  347.  --
  348.  --        The parameters: we ignore the PicHandle at this point and the str63 containing the 
  349.  --        name for the title bar of the window is used.
  350.  --
  351.  --        A boolean is returned indicating success.  Failure may result from an running out of 
  352.  --        memory in the heap.
  353.  --
  354.  **/
  355. Boolean CreateDocumentWindow(PicHandle thePicture, Str63 name)
  356. {
  357.     WindowPtr        theWindow;
  358.     ControlHandle    hControl, vControl;
  359.     Rect            controlRect, deviceRect, windRect, docRect = {0, 0, 1000, 1000};
  360.     Point            origin;
  361.  
  362.     /* Allocate space for window */
  363.     theWindow = (WindowPtr)NewPtr(sizeof(MyWindowRecord));
  364.     if (theWindow == nil)
  365.     {
  366.         ErrorAlert(kOutOfMemoryErr, false);
  367.         return(false);
  368.     }
  369.     GetNewWindow(rDocumentWindow, theWindow, (WindowPtr)-1);
  370.  
  371.     ((MyWindowPeek)theWindow)->documentBoundsRect = docRect;
  372.     SetPt(&((MyWindowPeek)theWindow)->origin, 0, 0);
  373.     SetWTitle(theWindow, name);
  374.  
  375.     windRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  376.  
  377.     windRect.right += kScrollBarWidth-1;
  378.     windRect.bottom += kScrollBarWidth-1;
  379.     OffsetRect(&windRect, -windRect.left, -windRect.top);    /* Adjust upper left to 0,0 */
  380.     if (windRect.right < kMinWindowWidth-1) windRect.right = kMinWindowWidth-1;
  381.     if (windRect.bottom < kMinWindowHeight-1) windRect.bottom = kMinWindowHeight-1;
  382.  
  383.     /* Allocate space for HORIZONTAL scroll bar */
  384.     SetRect(&controlRect, 0, 0, 100, 10);
  385.     hControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  386.     ((MyWindowPeek)theWindow)->hScrollBar = hControl;
  387.     if (hControl == nil)
  388.     {
  389.         CloseWindow(theWindow);
  390.         DisposePtr((Ptr)theWindow);
  391.         ErrorAlert(kOutOfMemoryErr, false);
  392.         return(false);
  393.     }
  394.     
  395.     /* Allocate space for VERTICAL scroll bar */
  396.     SetRect(&controlRect, 0, 0, 10, 100);
  397.     vControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  398.     ((MyWindowPeek)theWindow)->vScrollBar = vControl;
  399.     if (vControl == nil)
  400.     {
  401.         DisposeControl(hControl);
  402.         CloseWindow(theWindow);
  403.         DisposePtr((Ptr)theWindow);
  404.         ErrorAlert(kOutOfMemoryErr, false);
  405.         return(false);
  406.     }
  407.  
  408.     /* POSITION the new window */
  409.     if (FrontWindow() == nil)        /* no windows open, use default position */
  410.     {                                /* Align to upper left of main device */
  411.         OffsetRect(&windRect, 2, 2 + kTitleBarHeight+GetMBarHeight());
  412.         deviceRect = qd.screenBits.bounds;
  413.         deviceRect.left += 3;
  414.         deviceRect.top += 3+GetMBarHeight()+kTitleBarHeight;
  415.         deviceRect.right -= 3;
  416.         deviceRect.bottom -= 3;
  417.     }
  418.     else    /* Position down and right from frontmost window */
  419.     {
  420.         SetPort(FrontWindow());
  421.         SetPt(&origin, 0, 0);
  422.         LocalToGlobal(&origin);
  423.         origin.h += kNewWindowOffset;
  424.         origin.v += kNewWindowOffset;
  425.         OffsetRect(&windRect, origin.h, origin.v);
  426.         deviceRect = GetDeviceRect(FrontWindow());
  427.     }
  428.  
  429.     /* Adjust size and position for display        */
  430.     /* If not enough room for entire window:    */
  431.     /* 1. Position in upper left                */
  432.     /* 2. Resize to fit on screen                */
  433.     FitWindowOnDevice(&windRect, &deviceRect);
  434.     MoveWindow(theWindow, windRect.left, windRect.top, true);
  435.     SizeWindow(theWindow, windRect.right-windRect.left,
  436.                 windRect.bottom-windRect.top, false);
  437.     
  438.     ResizeScrollBars(theWindow);        /* Initialize Scroll Bars */
  439.  
  440.     ShowControl(hControl);
  441.     ShowControl(vControl);
  442.     ShowWindow(theWindow);
  443.  
  444.     //
  445.     //    We need to attach a couple of viewPorts to the window to allow our
  446.     //    QuickDraw GX shapes to be clipped and scrolled correctly.     
  447.     //                                                                (QuickDraw GX Scrolling)    
  448.     //
  449.     {
  450.         gxRectangle    viewRect;
  451.         gxViewPort    windowParentViewPort;
  452.         gxShape        contentViewPortShape;
  453.         
  454.         //
  455.         //    Get a rectangle shape which represents the portRect of the window. This
  456.         //    shape will be used as the clip shape for the "gcontentViewPort". This
  457.         //  viewPort will have all of our QuickDraw GX objects drawn to.
  458.         //
  459.         TranslateWindowBounds(theWindow, &viewRect);
  460.  
  461.         //
  462.         //     Adjust our viewRect to accommodate the scroll bars
  463.         //
  464.         viewRect.right -= ff(kScrollBarWidth - 1);    
  465.         viewRect.bottom -= ff(kScrollBarWidth - 1);
  466.  
  467.         //
  468.         //    Add a viewPort to the window. This will enable the user to move the 
  469.         //    window around and have our QuickDraw GX objects drawn into this window.
  470.         //    
  471.         windowParentViewPort = GXNewWindowViewPort(theWindow);
  472.  
  473.         //
  474.         //    Create a second viewPort and attached it to the "parent" viewPort of our 
  475.         //    window. You cannot manipulate the parent viewPort attached to a window,
  476.         //    but you can manipulate it's children. We will manipulate the clip and 
  477.         //    mapping of this viewPort when the user resizes the window or scrolls it's 
  478.         //    contents. Also, we need this child viewPort because we want to set the clip 
  479.         //    shape of the window to reside within the scroll bars, not on top of them,
  480.         //    which would be the case if we only used the parent viewPort.
  481.         // 
  482.         gcontentViewPort = GXNewViewPort(GXGetViewPortViewGroup(windowParentViewPort));
  483.          
  484.         //
  485.         //    Set up the shape, clip and, mapping of our "gcontentViewPort". We will
  486.         //    then attached it to the "parent" viewPort of the window.
  487.         //
  488.         contentViewPortShape = GXNewRectangle(&viewRect);
  489.         GXSetViewPortClip(gcontentViewPort, contentViewPortShape);
  490.         GXSetViewPortMapping(gcontentViewPort, nil);
  491.         GXSetViewPortParent(gcontentViewPort, windowParentViewPort);
  492.         GXDisposeShape (contentViewPortShape);
  493.  
  494.         //
  495.         //    By calling SetDefaultViewPort (..), all shapes we create will 
  496.         //    be automatically drawn to "gcontentViewPort".
  497.         // 
  498.         SetDefaultViewPort(gcontentViewPort);            
  499.     
  500.         gthePage = CreateThePageOfGXShapes (nil);
  501.     }
  502.  
  503.     return(true);
  504. }
  505.  
  506.  
  507.  
  508. /**----- CreateThePageOfGXShapes -------------------------------------------------------------
  509.  --
  510.  --        This function creates a GX picture containing the shapes which will be displayed
  511.  --        within our window. In this case, all of the shapes will be rectangles
  512.  --                                                                       (QuickDraw GX Addition)
  513.  **/
  514. gxShape CreateThePageOfGXShapes (gxShape thePage)
  515. {
  516.     //
  517.     //    If the picture passed in has not been created, create an empty GX picture. We set
  518.     //    the "uniqueItemsShape" attribute because we are adding the same rectangle multiple
  519.     //    times. This guarantees that each rectagnle will have a "unique" reference within
  520.     //    the picture. Otherwise, you would only see the last rectangle added to the picture.
  521.     //
  522.     if (thePage == nil) 
  523.     {
  524.         thePage = GXNewShape(gxPictureType);
  525.         GXSetShapeAttributes(thePage, gxUniqueItemsShape);
  526.     }
  527.     
  528.     //
  529.     //    Create the shapes displayed into the window.
  530.     //
  531.     thePage = CreateTextShape (thePage);
  532.  
  533.     thePage = CreateLayoutShape (thePage);
  534.  
  535.     return (thePage);
  536. }
  537.     
  538.  
  539. /**----- CreateTextShape ---------------------------------------------------------------------
  540.  --
  541.  --        This function creates a text shape, converts it to a path shape, and fills it with
  542.  --        a polygon shape which is a star. We will then frame the shape filled with stars.
  543.  --        Finally, we add these two path shapes to the GX picture which was passed into this
  544.  --        function.
  545.  --                                                                       (QuickDraw GX Addition)
  546.  **/
  547. gxShape CreateTextShape (gxShape thePage)
  548. {
  549.     gxShape            tempTextShape;
  550.     gxPoint            textPostion = {ff(45),ff(225)};
  551.     
  552.     gxShape         starShape;
  553.     gxRectangle     starShapeBounds;
  554.     gxPatternRecord    starPattern;
  555.     
  556.     long starGeometry[] = {    1,                 //  number of contours
  557.                             5,                 //  number of points 
  558.                               ff(60), 0,         //  the points
  559.                               ff(90), ff(90),  
  560.                               0, ff(30),  
  561.                               ff(120), ff(30), 
  562.                               0, ff(90)};   
  563.     //
  564.     //  Create the text, set the font, and size.
  565.     //
  566.     tempTextShape = GXNewText(2,(unsigned char*)"GX", &textPostion);
  567.     GXSetShapeTextSize(tempTextShape, ff(250));
  568.  
  569.     SetShapeCommonFont(tempTextShape, newyorkFont);  // This call comes from the "font library"
  570.  
  571.  
  572.     //
  573.     //    We need to convert our text shape to a path shape. Why? We want to fill our text shape
  574.     //    with stars, but you can only fill geometric shapes with other geometric shapes. So, we 
  575.     //    convert it. We set the shape type, pen, and pen location. We set the pen location to be
  576.     //    "gxOutsideFrameStyle" which tells GX graphics to place the pen on the outside of the 
  577.     //    contour of our path shape. Finally, we set the color of our frame to be magenta. The
  578.     //    SetShapeCommonColor call is a library call which creates the magenta color in the RGB
  579.     //    color space and colors our shape.
  580.     //
  581.     GXSetShapeType(tempTextShape, gxPathType);
  582.     GXSetShapeFill(tempTextShape, gxClosedFrameFill);
  583.     GXSetShapeStyleAttributes(tempTextShape, gxOutsideFrameStyle);
  584.     GXSetShapePen(tempTextShape, ff(3));
  585.     
  586.     SetShapeCommonColor (tempTextShape, magenta);
  587.  
  588.     //
  589.     //    We scale our shape 125% in the x-direction and 65% in the y-direction to get 
  590.     //    our "GX" path shape to have the fat tall look. 
  591.     //
  592.     GXScaleShape(tempTextShape, fl(1.25), fl(0.65), 0, 0);
  593.  
  594.  
  595.     //
  596.     //    We add the framed version of our path to our GX picture shape. Anytime, we draw the
  597.     //    picture - thePage , the framed path will be drawn. In this case, we add our path
  598.     //    to the end of the picture.
  599.     //
  600.     GXSetPictureParts(thePage, 0, 0, 1, &tempTextShape, nil, nil, nil);
  601.     
  602.     
  603.     //
  604.     //    We change our path's shape fill to be solidFill. Why? When you add a pattern to a shape
  605.     //    it fills to the shape fill. Before we changed the fill to solidFill, it was set to frame
  606.     //    fill, it would be a little difficult to see the stars with a frame thickness of only 3.
  607.     //
  608.     GXSetShapeFill(tempTextShape, gxSolidFill);
  609.     SetShapeCommonColor (tempTextShape, cold_grey);
  610.  
  611.  
  612.     //
  613.     // Create a star shape which will be used as the fill pattern
  614.     //
  615.     starShape = GXNewPolygons((gxPolygons *) starGeometry);
  616.     GXScaleShape(starShape, fl(0.15), fl(0.15), 0, 0);
  617.  
  618.  
  619.     //
  620.     //    Get the bounds of our star shape.  We use the bounds to setup the u and v vectors of the pattern 
  621.     //    record. We want "tempTextShape" to be filled with the stars where each star is placed at edge
  622.     //     of the previous star (i.e so the star pattern does not overlap).
  623.     //    
  624.     GXGetShapeBounds(starShape, 0L, &starShapeBounds);
  625.  
  626.     //
  627.     //    Set up the pattern record containing the star information.
  628.     //
  629.     starPattern.u.x = 0;
  630.     starPattern.u.y = starShapeBounds.bottom;
  631.     starPattern.v.x = starShapeBounds.right + fix1;
  632.     starPattern.v.y = 0;
  633.  
  634.     starPattern.attributes = gxNoAttributes;
  635.     starPattern.pattern = starShape;
  636.  
  637.  
  638.     //
  639.     //    Add the star pattern to the style of our "tempTextShape" whihc is now a path and add it 
  640.     //    to the end of our GX picture - thePage.
  641.     //
  642.     GXSetShapePattern(tempTextShape, &starPattern);
  643.     GXSetPictureParts(thePage, 0, 0, 1, &tempTextShape, nil, nil, nil);
  644.     
  645.     //
  646.     //    We can dispose of our star shape because it is now referenced from within the
  647.     //    pattern record contained in "gShape".
  648.     //
  649.     GXDisposeShape (starShape);
  650.     GXDisposeShape (tempTextShape);
  651.     
  652.     return (thePage);
  653. }
  654.  
  655.  
  656.  
  657. /**----- CreateLayoutShape -------------------------------------------------------------------
  658.  --
  659.  --        This function creates a GX picture containing the shapes which will be displayed
  660.  --        within our window. In this case, all of the shapes will be rectangles
  661.  --                                                                       (QuickDraw GX Addition)
  662.  **/
  663. gxShape CreateLayoutShape (gxShape thePage)
  664. {
  665.     gxShape            tempLayoutShape;
  666.     char             *sampleText = "Catch the Nasty WAVE, Dude";
  667.     gxPoint         layoutPosition = {ff(45), ff(240)};
  668.  
  669.     gxRunControls    runControls;
  670.     gxRunFeature    runFeatures[3];
  671.     gxStyle            styles[3];
  672.  
  673.     short            totalLengthOfLayout, 
  674.                     lengthsArray[3],
  675.                     loop;
  676.  
  677.     //    
  678.     //    We start by intializing the layout run controls to their default values.
  679.     //
  680.     InitializeRunControls(&runControls);
  681.  
  682.  
  683.     //
  684.     //    We need to create the style which will be used for the first run of text within our
  685.     //    layout shape: "Catch the Nasty". Within a layout shape, you have the ability to have
  686.     //    multiple runs of text. Each run can use: a different font, text size, run features,
  687.     //    run controls.
  688.     //    
  689.     //    In the case of our first run of text, we want to use Hoefler Italic and a text size of 36.
  690.     //    We set the run controls to their default setting. 
  691.     //
  692.     styles[0] = NewLayoutStyle((char *)"\pHoefler Italic", ff(36), 0, &runControls, nil, 0, nil);
  693.     
  694.     
  695.     //
  696.     //    Next, we want to turn on a couple of run features within this run of text. We start by
  697.     //    enabling the "as" ligature in "Nasty". We our runFeature  we want to set the 
  698.     //    featureType of our run control to enable the ligature capabilities of Hoefler Italic, and
  699.     //    we then enable the "as" ligature. 
  700.     //
  701.     runFeatures[0].featureType = gxLigatureType;
  702.     runFeatures[0].featureSelector = gxLigatureRareOnSelector;
  703.     
  704.     
  705.     //
  706.     //    The next thing we need to setup our second runFeatures to enable the swash capabilities for 
  707.     //    our"C", "N", "D" characters contained within the first run of text. These swashes are part of the 
  708.     //    Hoefler Italic font. We acheive this goal by setting the runFeatures featureType
  709.     //    to gxAlternateDesignsType, telling line layout we want swashes for the appropriate 
  710.     //    characters within this run of text, and we enable the featureSelector
  711.     //
  712.     runFeatures[1].featureType = gxAlternateDesignsType;
  713.     runFeatures[1].featureSelector = gxAlternateDesignsChanceryOnSelector;
  714.  
  715.     //
  716.     //  Now we add the two run features to the style used by this run of text:
  717.     //
  718.     GXSetStyleRunFeatures(styles[0], 2, runFeatures);
  719.  
  720.     //     
  721.     //    In the second style we need to create is for the "WAVE!" run. For this run of text, 
  722.     //    we want the font to be Times Roman, 38 point text size, and use the default run 
  723.     //    controls. This style will also give us automatic kerning of the run.
  724.     //
  725.     styles[1] = NewLayoutStyle((char *)"\pTimes Roman", ff(38), 0, &runControls, nil, 0, nil);
  726.     
  727.     
  728.     //
  729.     //    The final style we need to create is used by the last run of text "dude". 
  730.     //
  731.     styles[2] = NewLayoutStyle((char *)"\pHoefler Italic", ff(40), 0, &runControls, nil, 0, nil);
  732.  
  733.     //
  734.     //    The third run features used for the style reference by the last run of text will
  735.     //    enable the final form of "e" in "dude". We enable these smartSwashType feature and
  736.     //    turn on the final form of "e".
  737.     //
  738.     runFeatures[2].featureType = gxSmartSwashType;
  739.     runFeatures[2].featureSelector = gxSmartSwashLineFinalsOnSelector;
  740.  
  741.  
  742.     //
  743.     //    Update the style used for this run of text to use the our run features which
  744.     //    enable the final form "e".
  745.     //
  746.     GXSetStyleRunFeatures(styles[2], 3, runFeatures);
  747.  
  748.  
  749.     lengthsArray[0] = 15;   lengthsArray[1] = 6;   lengthsArray[2] = 5;
  750.  
  751.     totalLengthOfLayout = 26;
  752.     
  753.     //
  754.     //     We now have all the information required to define our layout shape and add 
  755.     //     it to our picture stored in the variable gthePage. Our layout shape will contain
  756.     //     three runs of text using three different styles. Each style will use a different
  757.     //     text size. Two different fonts will be used, and three run features will be enabled.
  758.     //     The definition looks like this:
  759.     //
  760.     tempLayoutShape = GXNewLayout(    1, 
  761.                                     &totalLengthOfLayout,
  762.                                     (void *) &sampleText, 
  763.                                     3,
  764.                                     lengthsArray,
  765.                                     styles, 
  766.                                     0, nil, nil, nil, &layoutPosition);
  767.  
  768.     GXSetPictureParts(thePage, 0, 0, 1, &tempLayoutShape, nil, nil, nil);
  769.  
  770.  
  771.     GXSkewShape(tempLayoutShape, fl(1.25), 0, layoutPosition.x, layoutPosition.y);
  772.     GXMoveShape (tempLayoutShape, ff(15), ff(75));
  773.  
  774.      GXSetPictureParts(thePage, 0, 0, 1, &tempLayoutShape, nil, nil, nil);
  775.  
  776.     //
  777.     //    Dispose of all of the QuickDraw GX objects which are no longer needed.
  778.     //
  779.     GXDisposeShape (tempLayoutShape);
  780.     
  781.     for (loop = 0; loop <= 2; loop++)
  782.       GXDisposeStyle(styles[loop]);
  783.  
  784.     return (thePage);
  785. }
  786.  
  787.  
  788.  
  789. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  790. //
  791. //    The following two functions: TranslateWindowBounds and ResetContentViewPortClip
  792. //
  793. //    Are utility functions used by this application to work between the QuickDraw based
  794. //    window world and QuickDraw GX viewPort world. TranslateWindowBounds converts the 
  795. //    QuickDraw portRect to a QuickDraw GX fixed point rectangle and ResetContentViewPortClip
  796. //    resets the content's viewPort clip (i.e. the child viewport attached to the parent window
  797. //    viewport).
  798. //    
  799. //•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  800.  
  801.  
  802. /**----- TranslateWindowBounds ---------------------------------------------------------------
  803.  --
  804.  --        This function returns a fixed point rectangle which represents the portRect of the
  805.  --        window. The shape returned is used as the new clip shape for the gcontentViewPort.
  806.  --
  807.  --                                                                    (QuickDraw GX Scrolling) 
  808.  **/
  809. void TranslateWindowBounds(WindowPtr myWindow, gxRectangle *boundingBoxPtr)
  810. {
  811.     GrafPtr        oldPort;
  812.     Rect        qdBounds;
  813.     gxRectangle    gxBounds;
  814.  
  815.     GetPort(&oldPort);
  816.     SetPort(myWindow);
  817.  
  818.     qdBounds = myWindow->portRect;        // this is in globals coordinates
  819.  
  820.     //
  821.     //    Convert the QuickDraw rectangle into a QuickDraw GX fixed point rectangle.
  822.     //
  823.     GXQDGlobalToFixedLocal((Point *) &qdBounds.top, (gxPoint *) &gxBounds.left );
  824.     GXQDGlobalToFixedLocal((Point *) &qdBounds.bottom, (gxPoint *) &gxBounds.right );
  825.  
  826.     *boundingBoxPtr = gxBounds;
  827.  
  828.     SetPort(oldPort);
  829. }
  830.  
  831.  
  832.  
  833. /**----- ResetContentViewPortClip ------------------------------------------------------------
  834.  --
  835.  --        This function resets the clip shape of the "gcontentViewPort", to represent the new
  836.  --        clip shape after the user has zoomed or resized the window.           
  837.  --                                                                    (QuickDraw GX Scrolling) 
  838.  **/
  839. void ResetContentViewPortClip (WindowPtr theWindow)
  840. {
  841.     gxRectangle    viewRect;
  842.     gxShape        contentViewPortClipShape;
  843.  
  844.     //
  845.     //    Return a fixed point rectangle in "viewRect" which represents the portRect of the
  846.      //    window. This shape will be used as the new clip shape for "gcontentViewPort".
  847.     TranslateWindowBounds(theWindow, &viewRect);
  848.  
  849.     //
  850.     // Adjust our viewRect to accommodate the scroll bars
  851.     //
  852.     viewRect.right -= ff(kScrollBarWidth - 1);    
  853.     viewRect.bottom -= ff(kScrollBarWidth - 1);
  854.  
  855.     //
  856.     //    Create and set the new clip shape.
  857.     //
  858.     contentViewPortClipShape = GXNewRectangle(&viewRect);
  859.     GXSetViewPortClip(gcontentViewPort, contentViewPortClipShape);
  860.  
  861.     GXDisposeShape (contentViewPortClipShape);
  862. }
  863.  
  864. //•-• End QuickDraw GX Utilities •-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•-•
  865.  
  866.  
  867.  
  868.  
  869.  
  870. /**----- ToolBoxInit -------------------------------------------------------------------------
  871.  --
  872.  --        This function initializes the toolbox.
  873.  --
  874.  **/
  875. void ToolBoxInit(void)
  876. {
  877.     EventRecord    theEvent;
  878.     short        count;
  879.     
  880.     /**   Generic heap initialization.  **/
  881.     MaxApplZone(); 
  882.     MoreMasters(); MoreMasters(); MoreMasters(); 
  883.     MoreMasters(); MoreMasters(); MoreMasters(); 
  884.  
  885.     InitGraf (&qd.thePort);
  886.     InitFonts ();
  887.     FlushEvents(everyEvent, 0);
  888.     InitWindows();
  889.     InitMenus();
  890.     TEInit();
  891.     InitDialogs(nil);
  892.     InitCursor();
  893.     
  894.     /* Multi-finder brings our application to the front after */
  895.     /* we ask for three events. */
  896.     for (count=3; count!=0; count--)
  897.         EventAvail(everyEvent, &theEvent);
  898. }
  899.  
  900.  
  901. /**----- MenuBarInit -------------------------------------------------------------------------
  902.  --
  903.  --     This function initializes the menus, and installs DAs in the Apple Menu.
  904.  --
  905.  **/
  906. void MenuBarInit(void)
  907. {
  908.     Handle        theMenuBar;
  909.     MenuHandle    appleMenu;
  910.     
  911.     /* Install menus from resources */
  912.     theMenuBar = GetNewMBar(rMenuBar);
  913.     if (theMenuBar == nil)
  914.         ErrorAlert(kNoMenuBarErr, true);
  915.     SetMenuBar(theMenuBar);
  916.     DisposHandle(theMenuBar);
  917.     
  918.     /* Add desk accessories to Apple Menu */
  919.     appleMenu = GetMHandle(mApple);
  920.     if (appleMenu != nil)
  921.         AddResMenu(appleMenu, kDriverType);
  922.  
  923.     DrawMenuBar();
  924. }
  925.  
  926.  
  927.  
  928. /**----- HandleEvent -------------------------------------------------------------------------
  929.  --
  930.  --        This function contains the main event loop.
  931.  --
  932.  **/
  933. void HandleEvent(void)
  934. {
  935.     EventRecord    theEvent;
  936.     OSErr        myErr;
  937.     WindowPtr    theWindow;
  938.     
  939.     WaitNextEvent(everyEvent, &theEvent, 30, nil);
  940.  
  941.     switch (theEvent.what)
  942.     {
  943.     case mouseDown:
  944.         HandleMouseDown(&theEvent);
  945.         break;
  946.     
  947.     case keyDown:
  948.     case autoKey:
  949.         HandleKeyPress(&theEvent);
  950.         break;
  951.     
  952.     case updateEvt:
  953.         theWindow = (WindowPtr)theEvent.message;
  954.         BeginUpdate(theWindow);
  955.         if (!EmptyRgn(theWindow->visRgn))
  956.         {
  957.             SetPort(theWindow);
  958.             UpdtControl(theWindow, theWindow->visRgn);
  959.             DrawGrowIcon(theWindow);
  960.             DrawWindow(theWindow);
  961.         }
  962.         EndUpdate(theWindow);
  963.     
  964.     case diskEvt:
  965.         HandleDiskEvent(&theEvent);
  966.         break;
  967.  
  968.     case activateEvt:
  969.         ActivateWindow((WindowPtr)theEvent.message, theEvent.modifiers & activeFlag);
  970.         break;
  971.     
  972.     case osEvt:
  973.         HandleOSEvent(&theEvent);
  974.         break;
  975.     
  976.     case kHighLevelEvent:
  977.         myErr = AEProcessAppleEvent(&theEvent);
  978.         if  (myErr != noErr)
  979.         {
  980.             ErrorAlert(kAppleEventErr, false);
  981.         }
  982.         break;
  983.     }
  984. }
  985.  
  986.  
  987. /**----- HandleMouseDown ---------------------------------------------------------------------
  988.  --
  989.  --        This functions is called whenever the mouse button is pressed. It finds the mouse 
  990.  --        location when the button was pressed and routes the event appropriately.
  991.  --
  992.  **/
  993. void HandleMouseDown(EventRecord *theEvent)
  994. {
  995.     short            thePart;
  996.     WindowPtr        theWindow;
  997.     Rect            theRect;
  998.     short            controlPart;
  999.     ControlHandle    theControl;
  1000.  
  1001.     thePart = FindWindow(theEvent->where, &theWindow);
  1002.     switch (thePart)
  1003.     {
  1004.     case inMenuBar:
  1005.         AdjustMenus();
  1006.         DoMenu(MenuSelect(theEvent->where));
  1007.         break;
  1008.     
  1009.     case inSysWindow:
  1010.         SystemClick(theEvent, theWindow);
  1011.         break;
  1012.     
  1013.     case inContent:
  1014.         if (theWindow != FrontWindow())
  1015.             SelectWindow(theWindow);
  1016.         else
  1017.         {
  1018.             SetPort(theWindow);
  1019.             GlobalToLocal(&theEvent->where);
  1020.             controlPart = FindControl(theEvent->where, theWindow, &theControl);
  1021.             if (controlPart != 0)
  1022.                 DoControl(theEvent->where, theControl, controlPart);
  1023.         }
  1024.         break;
  1025.  
  1026.     case inDrag:
  1027.         if (theWindow != FrontWindow())
  1028.             SelectWindow(theWindow);
  1029.         theRect = (**GetGrayRgn()).rgnBBox;
  1030.         DragWindow(theWindow, theEvent->where, &theRect);
  1031.         break;
  1032.     
  1033.     case inGrow:
  1034.         DoGrowWindow(theWindow, theEvent->where);
  1035.         break;
  1036.  
  1037.     case inGoAway:
  1038.         if (TrackGoAway(theWindow, theEvent->where))
  1039.           ShutdownProgram();
  1040.         break;
  1041.     
  1042.     case inZoomIn:
  1043.     case inZoomOut:
  1044.         if (TrackBox(theWindow, theEvent->where, thePart))
  1045.             DoZoomWindow(theWindow, thePart);
  1046.         break;
  1047.     }
  1048. }
  1049.  
  1050.  
  1051. /**----- DoGrowWindow ------------------------------------------------------------------------
  1052.  --
  1053.  --        This function takes care of growing a window after the mouse has been pressed over
  1054.  --        the grow icon.  It allows maximum growth of the document size or display size, whichever
  1055.  --        is smaller. It allows minimum growth to (kMinWindowWidth,kMinWindowHeight) or the 
  1056.  --        document size, whichever is larger. Finally, it adjusts and redraws the scroll bars 
  1057.  --        for the new window size.
  1058.  --
  1059.  **/
  1060. void DoGrowWindow(WindowPtr theWindow, Point where)
  1061. {
  1062.     Rect        growRect, windRect;
  1063.     Rect        thePage;
  1064.     short        width, height;
  1065.     long        newSize;
  1066.     Point        origin;
  1067.  
  1068.     thePage = ((MyWindowPeek)theWindow)->documentBoundsRect;
  1069.  
  1070.     width = thePage.right - thePage.left + kScrollBarWidth;
  1071.     height = thePage.bottom - thePage.top + kScrollBarWidth;
  1072.  
  1073.     growRect = (**GetGrayRgn()).rgnBBox;
  1074.     if (theWindow->portRect.left + width < growRect.right)
  1075.        growRect.right = theWindow->portRect.left + width;
  1076.         
  1077.     if (theWindow->portRect.top + height < growRect.bottom)
  1078.          growRect.bottom = theWindow->portRect.top + height;
  1079.  
  1080.     // Minimum size is (kMinWindowWidth,kMinWindowHeight) 
  1081.     growRect.left = kMinWindowWidth;
  1082.     growRect.top = kMinWindowHeight;
  1083.     
  1084.     // Make sure maximum size is at least minimum size
  1085.     if (growRect.right < growRect.left) growRect.right = growRect.left;
  1086.     if (growRect.bottom < growRect.top) growRect.bottom = growRect.top;
  1087.  
  1088.     /* Allow user to grow the window, then resize it */
  1089.     newSize = GrowWindow(theWindow, where, &growRect);
  1090.     
  1091.     if (newSize != 0)
  1092.     {
  1093.         GrafPtr        saveport;
  1094.  
  1095.         InvalidateScrollBars(theWindow);
  1096.         SizeWindow(theWindow, LoWord(newSize), HiWord(newSize), true);
  1097.         InvalidateScrollBars(theWindow);
  1098.         ResizeScrollBars(theWindow);
  1099.  
  1100.         // 
  1101.         //    The user as grown the window, we need to update the clip shape of the contentviewPort
  1102.         //    we attached to the window earlier in the CreateDocumentWindow function. If we did not
  1103.         //    update the clip shape of the contentviewPort clip, we would draw through the scroll  
  1104.         //    bars on the next update event.                                (QuickDraw GX Scrolling)
  1105.         //
  1106.         ResetContentViewPortClip(theWindow);
  1107.  
  1108.         
  1109.         /* reposition document */
  1110.         origin = ((MyWindowPeek)theWindow)->origin;
  1111.         width = theWindow->portRect.right - theWindow->portRect.left - origin.h - width + 1;
  1112.         height = theWindow->portRect.bottom - theWindow->portRect.top - origin.v - height + 1;
  1113.         if (width < 0) width = 0;
  1114.         if (height < 0) height = 0;
  1115.  
  1116.         if ( (width > 0) || (height > 0) )
  1117.         {
  1118.             DoScroll(theWindow, width, height);
  1119.             ResizeScrollBars(theWindow);
  1120.         }
  1121.     }
  1122. }
  1123.  
  1124.  
  1125. /**----- DoZoomWindow ------------------------------------------------------------------------
  1126.  --
  1127.  --        This function zooms a window. It follows the new human interface guidelines be 
  1128.  --        dealing with multiple displays. To do this, every time the window is zoomed to the 
  1129.  --        standard state, it recalculates the standard state based on the display that contains
  1130.  --        the largest area of the window. This routine   was adapted from Macintosh Technical 
  1131.  --        Note #79: "_ZoomWindow".
  1132.  --
  1133.  **/
  1134. void DoZoomWindow(WindowPtr theWindow, short thePart)
  1135. {
  1136.     Rect                deviceRect, zoomRect;
  1137.     Point                offset;
  1138.     WStateDataHandle    windowState;
  1139.         
  1140.     SetPort(theWindow);
  1141.     EraseRect(&theWindow->portRect);
  1142.     if ( (thePart == inZoomOut) && (ColorQDAvail()) )
  1143.     {
  1144.         /* Get window location in global coordinates */
  1145.         SetPt(&offset, 0, 0);
  1146.         LocalToGlobal(&offset);
  1147.         
  1148.         deviceRect = GetDeviceRect(theWindow);
  1149.  
  1150.         zoomRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  1151.         zoomRect.right += kScrollBarWidth-1;
  1152.         zoomRect.bottom += kScrollBarWidth-1;
  1153.  
  1154.         OffsetRect(&zoomRect, -zoomRect.left, -zoomRect.top);    /* Adjust upper left to 0,0 */
  1155.  
  1156.         /* At least minimum window size */
  1157.         if (zoomRect.right < kMinWindowWidth-1) zoomRect.right = kMinWindowWidth-1;
  1158.         if (zoomRect.bottom < kMinWindowHeight-1) zoomRect.bottom = kMinWindowHeight-1;
  1159.  
  1160.         OffsetRect(&zoomRect, offset.h, offset.v);                /* Align to window */
  1161.         
  1162.         FitWindowOnDevice(&zoomRect, &deviceRect);
  1163.  
  1164.         windowState = (WStateDataHandle)((WindowPeek)theWindow)->dataHandle;
  1165.         (**windowState).stdState = zoomRect;
  1166.     }
  1167.     ZoomWindow(theWindow, thePart, true);
  1168.     InvalRect(&theWindow->portRect);
  1169.  
  1170.     ResizeScrollBars(theWindow);
  1171.  
  1172.     // 
  1173.     //    The user as grown the window, we need to update the "gcontentviewPort" we attached to 
  1174.     //    the window earlier in the CreateDocumentWindow (..) function. If we did not update, the
  1175.     //    contentviewPort clip, we would draw through the scroll bars on the next update event. 
  1176.     //                                                                    (QuickDraw GX Scrolling)
  1177.     //
  1178.     ResetContentViewPortClip(theWindow);
  1179. }
  1180.  
  1181.  
  1182.  
  1183. /**----- FitWindowOnDevice -------------------------------------------------------------------
  1184.  --
  1185.  --        This routine takes two rectangles as parameters. windRect is the location of the 
  1186.  --        window in global coordinates. deviceRect is the boundary of the device in global 
  1187.  --        coordinates. This routine fits windRect inside deviceRect.  windRect is  modified, 
  1188.  --        and upon completion, is where the window should be positioned.
  1189.  --
  1190.  --        Here's how the algorithm works:
  1191.  --        Attempt to leave the window in the same location.  If the window doesn't fit inside
  1192.  --        the deviceRect, move it to the upper left corner of deviceRect.  If the window still 
  1193.  --        doesn't fit, resize windRect to fit inside the maxRect.
  1194.  --
  1195.  --        NOTE: Both rectangles must be in the same coordinate system.
  1196.  --
  1197.  **/
  1198. void FitWindowOnDevice(Rect *windRect, Rect *deviceRect)
  1199. {
  1200.     Rect    theUnion;    
  1201.  
  1202.     UnionRect(windRect, deviceRect, &theUnion);
  1203.     if (!EqualRect(deviceRect, &theUnion))            /* window contained on screen? */
  1204.     {                                                /* no, move to upper left corner of maxRect */
  1205.         OffsetRect(windRect, deviceRect->left-windRect->left, deviceRect->top-windRect->top);
  1206.         UnionRect(windRect, deviceRect, &theUnion);
  1207.         if (!EqualRect(deviceRect, &theUnion))        /* window contained on screen? */
  1208.         {                                            /* no, resize window to fit */
  1209.             if (windRect->right > deviceRect->right)
  1210.                 windRect->right = deviceRect->right;
  1211.             if (windRect->bottom > deviceRect->bottom)
  1212.                 windRect->bottom = deviceRect->bottom;
  1213.         }
  1214.     }
  1215. }
  1216.  
  1217.  
  1218. /**----- GetDeviceRect -----------------------------------------------------------------------
  1219.  --
  1220.  --        This routine takes a WindowPtr as its parameter. It returns the boundary rectangle of
  1221.  --        the device that contains the largest area of that window. The rect is returned in 
  1222.  --        global coordinates.
  1223.  --
  1224.  **/
  1225. Rect GetDeviceRect(WindowPtr theWindow)
  1226. {
  1227.     Rect        deviceRect, windRect, theSect;
  1228.     GDHandle    nthDevice, dominantGDevice;
  1229.     long        sectArea, greatestArea;
  1230.     short        bias;
  1231.     Point        offset;
  1232.     
  1233.     /* Get portRect in global coordinates */
  1234.     windRect = theWindow->portRect;
  1235.     SetPt(&offset, 0, 0);
  1236.     LocalToGlobal(&offset);
  1237.     OffsetRect(&windRect, offset.h, offset.v);
  1238.  
  1239.     bias = kTitleBarHeight;
  1240.     windRect.top -= bias;
  1241.     
  1242.     /* This loop checks the window against all the gdRects in the gDevice list */
  1243.     /* and remembers which gdRect contains the largest portion of the window   */
  1244.     /* being zoomed. */
  1245.     nthDevice = GetDeviceList();
  1246.     greatestArea = 0;
  1247.     while (nthDevice != nil)
  1248.     {
  1249.         if (TestDeviceAttribute(nthDevice, screenDevice))
  1250.             if (TestDeviceAttribute(nthDevice, screenActive))
  1251.             {
  1252.                 SectRect(&windRect, &(**nthDevice).gdRect, &theSect);
  1253.                 sectArea = (long)(theSect.right - theSect.left) *
  1254.                                  (theSect.bottom - theSect.top);
  1255.                 if (sectArea > greatestArea)
  1256.                 {
  1257.                     greatestArea = sectArea;
  1258.                     dominantGDevice = nthDevice;
  1259.                 }
  1260.             }
  1261.         nthDevice = GetNextDevice(nthDevice);
  1262.     }
  1263.  
  1264.     /* Create a max zoom rectangle, accounting for menu bar height if on main screen */
  1265.     if (dominantGDevice == GetMainDevice())
  1266.         bias += GetMBarHeight();
  1267.     SetRect(&deviceRect, (**dominantGDevice).gdRect.left+3,
  1268.             (**dominantGDevice).gdRect.top+bias+3,
  1269.             (**dominantGDevice).gdRect.right-3,
  1270.             (**dominantGDevice).gdRect.bottom-3);
  1271.     
  1272.     return(deviceRect);
  1273. }
  1274.  
  1275.  
  1276. /**----- HandleKeyPress ----------------------------------------------------------------------
  1277.  --
  1278.  --        This function is called whenever a key is pressed. Since this program has no typed 
  1279.  --        input, we are only concerned about command key equivalent menu selections.
  1280.  --
  1281.  **/
  1282. void HandleKeyPress(EventRecord *theEvent)
  1283. {
  1284.     char        theChar;
  1285.  
  1286.     theChar = theEvent->message & charCodeMask;
  1287.     if ((theEvent->modifiers & cmdKey)!=0)
  1288.     {
  1289.         AdjustMenus();
  1290.         DoMenu(MenuKey(theChar));
  1291.     }
  1292. }
  1293.  
  1294.  
  1295.  
  1296. /**----- HandleDiskEvent ---------------------------------------------------------------------
  1297.  --
  1298.  --        This function checks whether the disk was successfully mounted. If it wasn't, the disk
  1299.  --        initialization package is invoked.
  1300.  --
  1301.  **/
  1302. void HandleDiskEvent(EventRecord *event)
  1303. {
  1304.     Point thePoint = {120, 120};
  1305.     
  1306.     if (HiWord(event->message) != noErr)
  1307.     {
  1308.         DILoad();
  1309.         DIBadMount(thePoint, event->message);    /* thePoint is ignored in sys 7+ */
  1310.         DIUnload();
  1311.     }
  1312. }
  1313.  
  1314.  
  1315. /**----- HandleOSEvent -----------------------------------------------------------------------
  1316.  --
  1317.  --        This function is called when OSEvents are received. It handles suspend, resume, and mouse 
  1318.  --        moved OSEvents.
  1319.  --
  1320.  **/
  1321. void HandleOSEvent(EventRecord *theEvent)
  1322. {
  1323.     WindowPtr    theWindow;
  1324.     
  1325.     switch ((theEvent->message >> 24) & 0x000000ff)
  1326.     {
  1327.     case suspendResumeMessage:
  1328.         if (theEvent->message & 0x00000001)        /* resume message */
  1329.         {
  1330.             SetCursor(&qd.arrow);
  1331.             theWindow = FrontWindow();
  1332.             if (theWindow != nil)
  1333.                 ActivateWindow(theWindow, true);    /* Activate front window */
  1334.             /* Copy contents of clipboard (if changed) to private scrap */
  1335.         }
  1336.         else    /* suspend message */
  1337.         {
  1338.             theWindow = FrontWindow();
  1339.             if (theWindow != nil)
  1340.                 ActivateWindow(theWindow, false);    /* Deactivate front window */
  1341.             /* Move private scrap to clipboard */
  1342.         }
  1343.         break;
  1344.     
  1345.     case mouseMovedMessage:
  1346.         break;
  1347.     }
  1348. }
  1349.  
  1350.  
  1351. /**----- CloseFrontWindow --------------------------------------------------------------------
  1352.  --
  1353.  --        This function closes the frontmost window and disposes of the window record allocated
  1354.  --        on the heap for it.
  1355.  --
  1356.  **/
  1357. void CloseFrontWindow(void)
  1358. {
  1359.     WindowPtr    theWindow;
  1360.     
  1361.     theWindow = FrontWindow();
  1362.     if (theWindow!=nil)
  1363.     {
  1364.         CloseWindow(theWindow);
  1365.         DisposePtr((Ptr)theWindow);
  1366.     }
  1367. }
  1368.  
  1369.  
  1370.  
  1371. /**----- DrawWindow --------------------------------------------------------------------------
  1372.  --
  1373.  --        This function draws the contents of the window without overwriting the scroll bars.
  1374.  --
  1375.  **/
  1376. void DrawWindow(WindowPtr theWindow)
  1377. {
  1378.     PicHandle    thePicture;
  1379.     Rect        tempRect;
  1380.     Point        origin;
  1381.     RgnHandle    saveClip;
  1382.  
  1383.     SetPort(theWindow);
  1384.  
  1385.     saveClip = NewRgn();        /* Remove scroll bar areas from clipRgn */
  1386.     GetClip(saveClip);
  1387.     tempRect = theWindow->portRect;
  1388.     tempRect.right -= (kScrollBarWidth-1);
  1389.     tempRect.bottom -= (kScrollBarWidth-1);
  1390.     ClipRect(&tempRect);
  1391.  
  1392.     SetClip(saveClip);            /* Restore clipRgn */
  1393.     DisposeRgn(saveClip);        
  1394.  
  1395.     //
  1396.     //    Draw the shapes contained within our GX picture shape - gthePage (QuickDraw GX Addition)
  1397.     // 
  1398.     GXDrawShape (gthePage);
  1399. }
  1400.  
  1401.  
  1402. /**----- ActivateWindow ----------------------------------------------------------------------
  1403.  --
  1404.  --        This function activates or deactivates a window, and is called when either an 
  1405.  --        activate/deactivate event or suspend/resume event is received. The parameters are a 
  1406.  --        window pointer to the desired window, and a boolean specifying whether to activate
  1407.  --        or deactivate the window.
  1408.  **/
  1409. void ActivateWindow(WindowPtr theWindow, Boolean activate)
  1410. {
  1411.     if (theWindow == nil)    /* safety check */
  1412.         return;
  1413.  
  1414.     if (activate)        /* activiate window */
  1415.     {
  1416.         /* Highlight controls */
  1417.         DrawGrowIcon(theWindow);
  1418.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 0);
  1419.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 0);
  1420.         /* Restore vertical bar or highlighting */
  1421.         /* Enable appropriate menu items */
  1422.     }
  1423.     else    /* deactivate window */
  1424.     {
  1425.         /* Unhighlight controls */
  1426.         DrawGrowIcon(theWindow);
  1427.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 255);
  1428.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 255);
  1429.         /* Remove vertical bar or highlighting */
  1430.         /* Disable appropriate menu items */
  1431.     }
  1432. }
  1433.  
  1434.  
  1435.  
  1436. /**----- DoMenu ------------------------------------------------------------------------------
  1437.  --
  1438.  --        This function is called when a menu item has been selected either with the mouse, 
  1439.  --        or a keyboard equivalent.
  1440.  --
  1441.  **/
  1442. void DoMenu(long menuChoice)
  1443. {
  1444.     short            theMenu;
  1445.     short            theItem;
  1446.     MenuHandle        appleMenu;
  1447.     Str255            accName;
  1448.     GrafPtr            savePort;
  1449.  
  1450.     theMenu = HiWord(menuChoice);
  1451.     theItem = LoWord(menuChoice);
  1452.     
  1453.     switch (theMenu)
  1454.     {
  1455.     case mApple:
  1456.         if (theItem == iAbout)
  1457.             Alert(rAboutBox, (ModalFilterProcPtr)nil);
  1458.         else
  1459.         {
  1460.             appleMenu = GetMHandle(mApple);
  1461.             if (appleMenu != nil)
  1462.             {
  1463.                 GetItem(appleMenu, theItem, accName);    /* Call desk accessory */
  1464.                 GetPort(&savePort);
  1465.                 OpenDeskAcc(accName);
  1466.                 SetPort(savePort);
  1467.             }
  1468.         }
  1469.         break;
  1470.         
  1471.     case mFile:
  1472.         switch (theItem)
  1473.         {
  1474.         case iOpen:
  1475.             break;
  1476.         
  1477.         case iClose:
  1478.             break;
  1479.         
  1480.         case iPrintOneCopy:
  1481.             DoPrintOneCopy (FrontWindow(), gDocumentJob, gthePage);
  1482.             break;
  1483.         
  1484.         case iDocumentSetup:
  1485.             DoDocumentSetupCommand(gDocumentJob);
  1486.             break;
  1487.         
  1488.         case iPageSetup:
  1489.             break;
  1490.         
  1491.         case iPrint:
  1492.             DoPrintCommand(FrontWindow(), gDocumentJob, gthePage);
  1493.             break;
  1494.         
  1495.         case iQuit:
  1496.             ShutdownProgram();
  1497.             break;
  1498.         }
  1499.         break;
  1500.     }
  1501.     HiliteMenu(0);
  1502. }
  1503.  
  1504.  
  1505.  
  1506. /**----- AdjustMenus -------------------------------------------------------------------------
  1507.  --
  1508.  --        This function is called immediately before each time the user makes a menu selection.
  1509.  --        It enables/disables the appropriate menu items based on the current state of the 
  1510.  --        program. In version 1.0, we do not update the menus. We only support "quit".
  1511.  **/
  1512. void AdjustMenus(void)
  1513. {
  1514.     WindowPtr    myWindow;
  1515.     MenuHandle    myFileMenu;
  1516.     
  1517.     myFileMenu = GetMHandle (mFile);
  1518.  
  1519.     myWindow = FrontWindow ();
  1520.  
  1521.     if (!myWindow && gQDGXPrintingInstalled)
  1522.     {
  1523.         DisableItem (myFileMenu, iPrintOneCopy);
  1524.         DisableItem (myFileMenu, iDocumentSetup);
  1525.         DisableItem (myFileMenu, iPrint);
  1526.     } else if (gQDGXPrintingInstalled)
  1527.              {
  1528.                 EnableItem (myFileMenu, iPrintOneCopy);
  1529.                 EnableItem (myFileMenu, iDocumentSetup);
  1530.                 EnableItem (myFileMenu, iPrint);
  1531.             }
  1532. }
  1533.  
  1534.  
  1535.  
  1536. /**----- ColorQDAvail ------------------------------------------------------------------------
  1537.  --
  1538.  --        This function is used before calling Color QuickDraw routines to see if they are 
  1539.  --        available.  Note that MPW 3.2 and THINK C 5.0 both include glue that let you use
  1540.  --        Gestalt even if it is not in ROM or in the System File. If you are not using one of 
  1541.  --        these environments, and you don't have Gestalt glue, you will need to use the 
  1542.  --        TrapAvailable check (as shown in Inside Macintosh VI 3-8) to determine whether the
  1543.  --     Gestalt call exists before calling it.
  1544.  --
  1545.  **/
  1546. Boolean ColorQDAvail(void)
  1547. {
  1548.     long    response;
  1549.     
  1550.     if (Gestalt(gestaltQuickdrawVersion, &response) == noErr)
  1551.         if ((response & 0x0000ffff) >= gestalt8BitQD)
  1552.             return(true);
  1553.     return(false);
  1554. }
  1555.  
  1556.  
  1557.  
  1558. /**----- ErrorAlert --------------------------------------------------------------------------
  1559.  --
  1560.  --        This function displays an error message in an alert.  The error number corresponds
  1561.  --         to an error message in a 'str#' resource.  This message is displayed in a dialog box.
  1562.  --          The Boolean parameter is true for a fatal error, and will cause the program to 
  1563.  --        immediately terminate instead of returning.
  1564.  --
  1565.  **/
  1566. void ErrorAlert(short errNumber, Boolean fatal)
  1567. {
  1568.     Str255    errorString;
  1569.     
  1570.     GetIndString(errorString, rErrorStrings, errNumber);
  1571.         
  1572.     ParamText(errorString, "\p", "\p", "\p");
  1573.     if (fatal)
  1574.     {
  1575.         StopAlert(rFatalErrorAlert, nil);
  1576.         ExitToShell();
  1577.     }
  1578.     else
  1579.         NoteAlert(rNonFatalErrorAlert, nil);
  1580. }
  1581.  
  1582.  
  1583.  
  1584. /**----- ShutdownProgram ---------------------------------------------------------------------
  1585.  --
  1586.  --        This function is called before normal termination of the program.  It sets the event
  1587.  --        loop done variable to true, so the program will exit at the end of the event loop. We
  1588.  --        call CloseFrontWindow() to dispose of our window and data structure containing our
  1589.  --        document information.
  1590.  --
  1591.  --        If this program had editing capabilities, this is where the user would be asked if 
  1592.  --        he wanted to save any changed documents before quitting.
  1593.  --
  1594.  **/
  1595. void ShutdownProgram(void)
  1596. {
  1597.     WindowPtr    theWindow;
  1598.     
  1599.     gDone = true;
  1600.     
  1601.     //     
  1602.     //    If we created a GX picture which contains our window full of information, we wnat to
  1603.     //    dispose of it, by callling DisposeShape. We call DisposeCommonColor () because we 
  1604.     //    initialized the common colors library earlier in the QuickDrawGXInit function.
  1605.     //                                                                  (QuickDraw GX Addition)
  1606.     if (gthePage != nil) GXDisposeShape(gthePage);  
  1607.  
  1608.        DisposeCommonColors();
  1609.  
  1610.     //
  1611.     //    This function call will dispose of the data contained in the window.
  1612.     //
  1613.     CloseFrontWindow();
  1614.     
  1615.     //
  1616.     //    If printing was installed by the user, we want to dispose of the "job" we created
  1617.     //    when we initialized the QuickDraw GX printing system.
  1618.     //
  1619.     if (gQDGXPrintingInstalled) TermintatePrintLand(gDocumentJob);
  1620.      
  1621.     //    
  1622.     //     Deallocate all of the default data and memory structures for the QuickDraw GX 
  1623.     //    graphics and layout system.                                        (QuickDraw GX Addition)
  1624.     //
  1625.     GXExitGraphics();        
  1626.     GXDisposeGraphicsClient(gGraphicsClient);
  1627. }
  1628.